﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;
using System.Xml.XPath;
using System.Xml.Xsl;

namespace Netfraction
{
    /// <summary>
    /// Interaction logic for FileListWindow.xaml
    /// </summary>
    public partial class FileListWindow : Window
    {
        static public List<DirectoryNode> directories;
        private Netfraction.Identity remoteIdentity;

        //private DCSharp.Runtime dcRuntime;

        public FileListWindow(/*DCSharp.Runtime dcRuntime,  */System.Xml.Linq.XDocument xDoc, Netfraction.Identity remoteIdentity)
        {
            InitializeComponent();
            
            directories = new List<DirectoryNode>();
            XDocument transformedDoc = new XDocument();
            try
            {

                using (XmlWriter writer = transformedDoc.CreateWriter())
                {
                    XslCompiledTransform transform = new XslCompiledTransform();
                    transform.Load(XmlReader.Create(new System.IO.FileStream(@"E:\ADC\SortNodes.xslt", System.IO.FileMode.Open, System.IO.FileAccess.Read)));
                    transform.Transform(xDoc.CreateReader(), writer);
                }
            }
            catch (System.Xml.Xsl.XsltException ex)
            {
                Console.WriteLine(ex.Message);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                throw;
            }
            this.DataContext = transformedDoc;
            this.remoteIdentity = remoteIdentity;

            //this.dcRuntime = dcRuntime;
            //LoadFileList();
        }

        #region old code
        /*private void LoadFileList()
        {
            string listPath = @"C:\Users\user\Desktop\files.xml";

            using (XmlTextReader reader = new XmlTextReader(listPath))
            {
                Load(reader);
            }
            XDocument doc = XDocument.Load(listPath);
            this.DataContext = doc;
        }

        private void Load(XmlTextReader reader)
        {
            // TODO: Load version, generator, etc.
            reader.ReadToFollowing("FileListing");
            string version = reader.GetAttribute("Cersion");
            string cid = reader.GetAttribute("CID");
            string baseDir = reader.GetAttribute("Base");
            string generator = reader.GetAttribute("Generator");

            Console.WriteLine(version);
            Console.WriteLine(cid);
            Console.WriteLine(baseDir);
            Console.WriteLine(generator);

            while (reader.ReadToFollowing("Directory"))
            {
                directories.Add(ReadDirectory(reader));
            }

        }

        private static DirectoryNode ReadDirectory(XmlReader reader)
        {
            DirectoryNode directory = new DirectoryNode(reader.GetAttribute("Name"));
            if (reader.IsEmptyElement)
            {
                return directory;
            }

            while (reader.Read())
            {
                if (reader.Name == "Directory" &&
                    reader.NodeType == XmlNodeType.EndElement)
                {
                    break;
                }

                if (reader.Name == "Directory" &&
                    reader.NodeType == XmlNodeType.Element)
                {
                    directory.Directories.Add(ReadDirectory(reader));
                }
                else if (reader.Name == "File" &&
                    reader.NodeType == XmlNodeType.Element)
                {
                    FileNode file = new FileNode(reader.GetAttribute("Name"),
                        long.Parse(reader.GetAttribute("Size")));

                    directory.Files.Add(file);
                }
            }
            return directory;
        }*/
        #endregion

        private void folderTreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            // Get the XPath address of the selected branch/department
            XElement xElem = e.NewValue as XElement;
            fileListView.ItemsSource = xElem.XPathSelectElements("File");
        }

        private XElement GetXElementFromDependencyObject(DependencyObject dep)
        {
            while ((dep != null) && !(dep is ListViewItem))
            {
                dep = VisualTreeHelper.GetParent(dep);
            }
            if (dep == null) return null;
            return ((XElement)fileListView.ItemContainerGenerator.ItemFromContainer(dep));
        }

        private void filesContextMenu_ContextMenuOpening(object sender, ContextMenuEventArgs e)
        {
            //DCSharp.Identity identity = GetIdentityFromDependencyObject((DependencyObject)e.OriginalSource);
            XElement xe = GetXElementFromDependencyObject((DependencyObject)e.OriginalSource);

            downloadFileMenuItem.Tag = xe;
        }

        private void downloadFileMenuItem_Click(object sender, RoutedEventArgs e)
        {
            XElement xe = (sender as MenuItem).Tag as XElement;
            Netfraction.ShareManager.VFSFileNode remFile =
                new Netfraction.ShareManager.VFSFileNode(null, 
                    xe.Attribute("Name").Value,
                    long.Parse(xe.Attribute("Size").Value),
                    DateTime.MinValue,
                    xe.Attribute("TTH").Value);
            //dcRuntime.DownloadManager.Download(remFile, remoteIdentity, ClientSettings.DownloadsDownloadFolder);
        }
    }

    public class XElementConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            XElement element = value as XElement;

            if (element == null) return null;
            return element.XPathSelectElements("Directory");
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    public class BytesConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value == null || value.ToString() == "0")
            {
                return "0 B";
            }

            double numBytes;
            if (!double.TryParse(value as string, out numBytes))
	        {
                numBytes = System.Convert.ToDouble(value);
            }
            string retString = "";

            if (numBytes < 0) return retString;
            if (numBytes < Math.Pow(2, 10))
            {
                retString = String.Format("{0} B", numBytes);
            }
            else if (numBytes < Math.Pow(2, 20))
            {
                retString = String.Format("{0} KB", Math.Round(numBytes / Math.Pow(2, 10), 2));
            }
            else if (numBytes < Math.Pow(2, 30))
            {
                retString = String.Format("{0} MB", Math.Round(numBytes / Math.Pow(2, 20), 2));
            }
            else if (numBytes < Math.Pow(2, 40))
            {
                retString = String.Format("{0} GB", Math.Round(numBytes / Math.Pow(2, 30), 2));
            }
            else if (numBytes < Math.Pow(2, 50))
            {
                retString = String.Format("{0} TB", Math.Round(numBytes / Math.Pow(2, 40), 2));
            }
            
            return retString;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    public class XFileElementConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            XElement element = value as XElement;

            if (element == null) return null;
            return element.XPathSelectElements("File");
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    public class HeaderToImageConverter : IValueConverter
    {
        public static HeaderToImageConverter Instance = new HeaderToImageConverter();

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            Uri uri;
            if ((bool)value == true)
            {
                uri = new Uri("pack://application:,,,/Images/Folder_Open.png");
            }
            else
            {
                uri = new Uri("pack://application:,,,/Images/Folder_Closed.png");
            }
            return new BitmapImage(uri);
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotSupportedException("Cannot convert back");
        }
    }

    public class PathFileTypeConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return ShellInfo.GetFileType(value as string, false);
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    public class PathToImageConverter : IValueConverter
    {
        public static PathToImageConverter Instance = new PathToImageConverter();

        public object Convert(object value, Type targetType,
            object parameter, CultureInfo culture)
        {
            return ShellInfo.GetIcon(value as string, false);
        }

        public object ConvertBack(object value, Type targetType,
            object parameter, CultureInfo culture)
        {
            throw new NotSupportedException("Cannot convert back");
        }
    }

    [ValueConversion(typeof(System.Collections.IList), typeof(System.Collections.IEnumerable))]
    public class TreeViewSortConverter : IValueConverter
    {
        public static TreeViewSortConverter Instance = new TreeViewSortConverter();

        public object Convert(object value, Type targetType,
            object parameter, CultureInfo culture)
        {
            var list = from p in (value as System.Collections.ObjectModel.ReadOnlyObservableCollection<object>)
                       /*orderby (p as XElement).Attribute("Name")*/
                       select p;
            ListCollectionView lcv = new ListCollectionView(list.ToList());
            System.ComponentModel.SortDescription sort = new System.ComponentModel.SortDescription(parameter.ToString(), System.ComponentModel.ListSortDirection.Ascending);

            lcv.SortDescriptions.Add(sort);

            Console.WriteLine(value.GetType().ToString());
            return lcv;
            //return value;
        }

        public object ConvertBack(object value, Type targetType,
            object parameter, CultureInfo culture)
        {
            throw new NotSupportedException("Cannot convert back in TreeViewSortConverter");
        }
    }

    public class DirectoryNode
    {
        private List<DirectoryNode> directories;
        private List<FileNode> files;
        private string name;

        public DirectoryNode(string name)
            : this()
        {
            this.name = name;
        }

        public DirectoryNode()
        {
            directories = new List<DirectoryNode>();
            files = new List<FileNode>();
        }

        #region Properties

        [XmlAttribute()]
        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        [XmlElement("Directory")]
        public List<DirectoryNode> Directories
        {
            get { return directories; }
            set { directories = value; }
        }

        [XmlElement("File")]
        public List<FileNode> Files
        {
            get { return files; }
            set { files = value; }
        }

        #endregion

        #region Methods

        public long GetSize()
        {
            long total = 0;
            foreach (DirectoryNode directory in directories)
            {
                total += directory.GetSize();
            }
            foreach (FileNode file in files)
            {
                total += file.Size;
            }
            return total;
        }

        #endregion
    }

    public class FileNode
    {
        private string name;
        private long size;

        public FileNode(string name, long size)
        {
            this.name = name;
            this.size = size;
        }

        public FileNode()
        {
        }

        #region Properties

        [XmlAttribute()]
        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        [XmlAttribute()]
        public long Size
        {
            get { return size; }
            set { size = value; }
        }

        #endregion
    }
}
